package hyl.core.net;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import hyl.core.AIni;
import hyl.core.Amy;
import hyl.core.MyFun;
import hyl.core.io.MyFile;
import hyl.core.safe.MyHash;


public class MyHttp {
	// 请求连接超时阈值
	public static int CONNECT_TIMEOUT = 5000; // in milliseconds
	// 文件上传或读取超时阈值
	public static int FILE_TIMEOUT = 120000;
	// 数据上传或读取超时阈值
	public static int DATA_TIMEOUT = 30000;
	public final static String CONTENTTYPE_JSON = "application/json;charset=UTF-8";
	public final static String CONTENTTYPE_FORM = "application/x-www-form-urlencoded";
	public final static String AGENT = "hyl.web/0.0.8";// "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)
														// like Gecko";

	/**
	 * PC授权回调
	 */
	public static String urlEncoded(String url) {
		try {
			if (url.charAt(0) == '%') // 防止已经加密过
				return url;
			return URLEncoder.encode(url, Amy.Charset);
		} catch (UnsupportedEncodingException e) {
			return "";
		}
	}

	/** contentType 为空时 默认是json 方式请求 */
	public static HttpURLConnection postData(String 请求方式, String urlStr, String data, String 返回格式, String charset) {
		URL url;
		HttpURLConnection conn;
		OutputStreamWriter writer = null;
		try {
			url = new URL(urlStr);
			conn = (HttpURLConnection) url.openConnection();

			conn.setDoOutput(true);// 是否输入参数
			conn.setDoInput(true); // 是否读取参数
			conn.setRequestMethod(请求方式);
			conn.setConnectTimeout(CONNECT_TIMEOUT);
			conn.setReadTimeout(DATA_TIMEOUT);
			返回格式 = MyFun.obj2Str(返回格式, CONTENTTYPE_JSON);
			if (charset.isEmpty())
				charset = Amy.Charset;

			conn.setRequestProperty("Accept-Charset", charset);
			conn.setRequestProperty("content-type", 返回格式);
			conn.setRequestProperty("User-Agent", AGENT);

			writer = new OutputStreamWriter(conn.getOutputStream(), charset);
			if (!MyFun.isEmpty(data)) {
				conn.setRequestProperty("Content-Length", String.valueOf(data.length()));
				writer.write(data);
				writer.flush();
			}
			writer.close();
			return conn;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();

		} finally {
			try {
				if (writer != null) {
					writer.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return null;
	}

	public static HttpURLConnection post(String urlStr, String 请求格式, String data) {
		return postData("POST", urlStr, data, 请求格式, Amy.Charset);
	}

	public static HttpURLConnection get(String urlStr, String 请求格式, String data) {
		return postData("GET", urlStr, data, 请求格式, Amy.Charset);
	}

	/**
	 * sendPost(http://localhost:8888/abc/a.jsp , "user=李刚&pass=abc");
	 * sendPost(http://localhost:8888/abc/a.jsp , "{user:xxx}"); 默认是json 方式请求
	 * CONTENTTYPE_JSON 可以改为 CONTENTTYPE_FORM 方式
	 */
	public static HttpURLConnection postJson(String urlStr, String data) {
		return postData("POST", urlStr, data, CONTENTTYPE_JSON, Amy.Charset);
	}

	public static HttpURLConnection postForm(String urlStr, String data) {
		return postData("POST", urlStr, data, CONTENTTYPE_FORM, Amy.Charset);
	}

	public static HttpURLConnection getJson(String urlStr, String data) {
		return postData("GET", urlStr, data, CONTENTTYPE_JSON, Amy.Charset);
	}

	/**
	 * 发送Post请求 默认是json方式请求
	 * 
	 * @param url
	 * @param parameterMap
	 * @return
	 * @throws Exception
	 */
	public static HttpURLConnection postForm(String urlStr, Map<String, String> parameterMap) {
		return sendPost(urlStr, parameterMap, CONTENTTYPE_FORM);
	}

	public static HttpURLConnection postJson(String urlStr, Map<String, String> parameterMap) {
		return sendPost(urlStr, parameterMap, CONTENTTYPE_JSON);
	}

	/** contentType 为空时 默认是json 方式请求 */
	public static HttpURLConnection sendPost(String urlStr, Map<String, String> parameterMap, String 返回格式) {
		StringBuilder parameterBuffer = new StringBuilder();
		if (parameterMap != null) {
			Iterator<String> iterator = parameterMap.keySet().iterator();
			String key = null;
			String value = null;
			while (iterator.hasNext()) {
				key = (String) iterator.next();
				if (parameterMap.get(key) != null) {
					value = (String) parameterMap.get(key);
				} else {
					value = "";
				}
				parameterBuffer.append(key).append("=").append(value);
				if (iterator.hasNext()) {
					parameterBuffer.append("&");
				}
			}
		}
		return postData("POST", urlStr, parameterBuffer.toString(), 返回格式, null);
	}

	/** 默认是form 方式请求 */
	public static HttpURLConnection sendGet(String urlStr) {
		return sendGet(urlStr, CONTENTTYPE_FORM);
	}

	/** contentType 为空时 默认是form 方式请求 */
	public static HttpURLConnection sendGet(String urlStr, String 返回格式) {
		URL url;
		HttpURLConnection conn;
		try {
			url = new URL(urlStr);
			conn = (HttpURLConnection) url.openConnection();
			conn.setDoOutput(false); // 是否输入参数
			conn.setDoInput(true); // 是否读取参数
			// conn.setRequestMethod(请求方式);
			conn.setConnectTimeout(CONNECT_TIMEOUT);
			conn.setReadTimeout(DATA_TIMEOUT);
			返回格式 = MyFun.obj2Str(返回格式, CONTENTTYPE_FORM);
			conn.setRequestProperty("Content-Type", 返回格式);
			conn.setRequestProperty("User-Agent", AGENT);

			return conn;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	public static String getResult(HttpURLConnection conn) {

		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), Amy.Charset));
			StringBuilder sb = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line);
				sb.append("\n");
			}
			return sb.toString();
		} catch (IOException e) {
		} finally {
			try {
				if (reader != null)
					reader.close();
			} catch (IOException e) {
			}
		}

		return null;
	}

	/**
	 * 
	 * @param text
	 * @param HtmlNodes
	 * @return
	 */

	public static String getHtml(String text, String[] 路径) {
		int i = 0, k = 0, j = 0;
		int n = 路径.length - 1;
		if (n > 0)
			for (j = 0; j < n; j++) {
				String s = 路径[j];
				i = text.indexOf(s, i);
				k = i;
				i = i + s.length();
				// System.out.println(i);
			}
		String endTag = 路径[j];
		int e = text.indexOf(路径[j], i);
		// System.out.println(e );
		// System.out.println(endTag.length() );
		// System.out.println(" -------------------- ");
		return text.substring(k, e + endTag.length());
	}

	/** 最后一个是结束符 */

	public static String getText(String text, String[] 路径) {
		int i = 0, j = 0;
		int n = 路径.length - 1;
		if (n > 0)
			for (j = 0; j < n; j++) {
				String s = 路径[j];
				i = text.indexOf(s, i);
				i = i + s.length();
			}

		int e = text.indexOf(路径[j], i);

		// System.out.println(i );
		// System.out.println(e );
		return text.substring(i, e);
	}

	static final String 换行 = "\r\n";
	static final String 块头 = "--";

	public static String upload(String actionUrl, List<File> uploadFiles) throws IOException {
		return upload(actionUrl, null, uploadFiles);
	}

	public static String upload(String actionUrl, File uploadFile) throws IOException {
		List<File> fs = new ArrayList<File>();
		fs.add(uploadFile);
		return upload(actionUrl, null, fs);
	}

	/**
	 * 返回空表示上传失败
	 * 
	 * @throws IOException
	 */
	public static String upload(String actionUrl, Map<String, String> params, List<File> uploadFiles) {
		String 块标签 = MyFun.getUUID();
		if (uploadFiles == null || uploadFiles.isEmpty()) {
			return null;
		}
		BufferedInputStream bis = null;
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		DataOutputStream ds = null;
		try {
			URL url = new URL(actionUrl);
			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			// 发送POST请求必须设置如下两行
			con.setConnectTimeout(CONNECT_TIMEOUT);
			con.setReadTimeout(FILE_TIMEOUT);
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false);
			con.setRequestMethod("POST");
			con.setRequestProperty("Connection", "Keep-Alive");
			con.setRequestProperty("Accept", "*/*");
			con.setRequestProperty("Accept-Encoding", "gzip, deflate");
			con.setRequestProperty("Cache-Control", "no-cache");
			con.setRequestProperty("Charset", Amy.Charset);
			con.setRequestProperty("User-Agent", AGENT);
			con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + 块标签);
			// 以上部分设置头；
			ds = new DataOutputStream(con.getOutputStream());
			if ((params != null) && (!params.isEmpty())) {
				for (Map.Entry<String, String> m : params.entrySet()) {
					multiparam(ds, 块标签, m.getKey(), m.getValue());
				}
			}
			for (int i = 0; i < uploadFiles.size(); i++) {
				File uploadFile = uploadFiles.get(i);
				multifile(ds, 块标签, "file" + i, uploadFile);
			}
			// 结束
			ds.writeBytes(块头 + 块标签 + 块头 + 换行);

			ds.flush();
			int code = 0;
			// 调用HttpURLConnection对象的getInputStream()方法构建输入流对象；
			// 调用HttpURLConnection对象的getResponseCode()获取客户端与服务器端的连接状态码。如果是200，则执行以下操作，否则返回null；
			if ((code = con.getResponseCode()) == 200) {
				bis = new BufferedInputStream(con.getInputStream());
				MyFile.in2out(baos, bis);
			}
			System.out.println("http230 行,上传返回码=" + code);
			// 将输入流转成字节数组，返回给客户端。
			return new String(baos.toByteArray(),AIni.charset);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (ds != null)
					ds.close();
				if (bis != null)
					bis.close();
				baos.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 传送文件
	 * 
	 * @param 输出
	 * @param 块标签
	 * @param 参数名
	 * @param uploadFile
	 * @throws IOException
	 */
	private static void multifile(DataOutputStream 输出, String 块标签, String 参数名, File uploadFile) throws IOException {
		// File uploadFile = uploadFiles.get(i);
		String filename = uploadFile.getName();
		输出.writeBytes(块头 + 块标签 + 换行);
		String s = "Content-Disposition: form-data; " + "name=\"" + 参数名 + "\";md5=\"" + MyHash.getInsMD5().parse(uploadFile)
				+ "\";filename=\"";
		// 注意DataOutputStream .writeBytes 在传输中文时会舍去高位byte
		输出.writeBytes(s);
		输出.write(filename.getBytes());
		输出.writeBytes("\"" + 换行);
		输出.writeBytes(换行);
		// 数据
		FileInputStream fis = new FileInputStream(uploadFile);
		MyFile.in2out(输出, fis);
		fis.close();
		输出.writeBytes(换行);
	}

	/**
	 * 传送文件时，带参数传
	 * 
	 * @param 输出
	 * @param 块标签
	 * @param 参数名
	 * @param 值
	 * @throws IOException
	 */
	private static void multiparam(DataOutputStream 输出, String 块标签, String 参数名, String 值) throws IOException {
		输出.writeBytes(块头 + 块标签 + 换行);
		输出.writeBytes("Content-Disposition: form-data; " + "name=\"" + 参数名 + "\";" + "\"" + 换行);
		输出.writeBytes(换行);
		// 数据
		MyFile.appendBytes(输出, 值.getBytes(AIni.charset));
		输出.writeBytes(换行);
	}

	public static String[] get外网IP() throws SocketException {
		Enumeration<?> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
		InetAddress ip = null;
		ArrayList<String> ips = new ArrayList<>();
		while (allNetInterfaces.hasMoreElements()) {
			NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
			// System.out.println(netInterface.getName());
			Enumeration<?> addresses = netInterface.getInetAddresses();
			while (addresses.hasMoreElements()) {
				ip = (InetAddress) addresses.nextElement();
				if (ip != null && ip instanceof Inet4Address && ip.isSiteLocalAddress()) {

					String s = ip.getHostAddress();

					// System.out.println(ip.getCanonicalHostName()+"::"+ip.getHostAddress()+":"+s);

					// System.out.println(s);
					ips.add(s);

				}
			}
		}
		if (ips.isEmpty())
			return new String[] { "127.0.0.1" };

		else
			return ips.toArray(new String[0]);

	}
}
